package com.kinyx.framework.db.sentence.res;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.persistence.metamodel.SingularAttribute;
import javax.util.XArrayList;

import com.kinyx.framework.annotation.assist.Tester;
import com.kinyx.framework.db.configs.DBConfigs;
import com.kinyx.framework.db.sentence.CompareType;
import com.kinyx.framework.db.sentence.LikeType;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

/**
 * 条件子句
 */
@Tester("com.kinyx.framework.db.sentence.res.Condition_Tester_Simple")
@Tester("com.kinyx.framework.db.sentence.res.Condition_Tester_Complex")
@Tester("com.kinyx.framework.db.sentence.res.Condition_Tester_Fix")
public class Condition extends _SentenceWithParams {

	/** 条件类型 null：子句；true：AND子句；fals：OR子句； */
	@Getter(value = AccessLevel.PACKAGE)
	@Setter(value = AccessLevel.PACKAGE)
	private Boolean conditionType;

	/** 表达式 */
	private _Expression expression;

	/** 条件列表 */
	private _Conditions conditions;

	/** true: 外层子句; false: 内层子句; */
	private boolean outer = true;

	@Override
	public String getSentence(final DBConfigs configs, final boolean isSQL, final boolean withTableAlias) {
		String sentence;
		if (this.expression != null) {// 普通条件
			sentence = this.expression.getSentence(configs, isSQL, withTableAlias);
		} else {// 复合条件
			sentence = this.conditions.getSentence(configs, isSQL, withTableAlias);
		}
		if (this.outer) {
			return sentence;
		} else {
			return String.format("(%s)", sentence);
		}
	}

	@Override
	public List<Object> getParams() {
		if (this.expression != null) {// 普通条件
			if (this.expression instanceof _Expression_COMPARE) {
				return new XArrayList<>().xAdd(((_Expression_COMPARE) this.expression).getParam());
			}
			if (this.expression instanceof _Expression_IN) {
				return new XArrayList<>().xAddAll(Arrays.asList(((_Expression_IN) this.expression).getParams()));
			}
			if (this.expression instanceof _Expression_LIKE) {
				return new XArrayList<>().xAdd(((_Expression_LIKE) this.expression).getParam());
			}
			return Collections.emptyList();
		} else {// 复合条件
			return this.conditions.getParams();
		}
	}

	// 普通条件
	private Condition(final Boolean conditonType, final _Expression expression) {
		this.conditionType = conditonType;
		this.expression = expression;
	}
	// 复合条件
	private Condition(final Boolean conditonType, final Condition condition) {
		this.conditionType = conditonType;
		this.conditions = new _Conditions();
		condition.outer = false;
		this.conditions.add(condition);
	}

	// ======================================================================================== of ======================================================================================== //
	// ============================================ column = ? ============================================ //
	// ============================================ columnX = columnY ============================================ //
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition eq(final Column column, final Object param) {
		if ((param != null) && (param instanceof Column)) {
			return new Condition(null, new _Expression_COMPARE_TO(column, CompareType.EQ, (Column) param));
		} else {
			return new Condition(null, new _Expression_COMPARE(column, CompareType.EQ, param));
		}
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition eq(final SingularAttribute<?, ?> column, final Object param) { return eq(Res.toCol(column), param); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition neq(final Column column, final Object param) {
		if ((param != null) && (param instanceof Column)) {
			return new Condition(null, new _Expression_COMPARE_TO(column, CompareType.NEQ, (Column) param));
		} else {
			return new Condition(null, new _Expression_COMPARE(column, CompareType.NEQ, param));
		}
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition neq(final SingularAttribute<?, ?> column, final Object param) { return neq(Res.toCol(column), param); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition lt(final Column column, final Object param) {
		if ((param != null) && (param instanceof Column)) {
			return new Condition(null, new _Expression_COMPARE_TO(column, CompareType.LT, (Column) param));
		} else {
			return new Condition(null, new _Expression_COMPARE(column, CompareType.LT, param));
		}
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition lt(final SingularAttribute<?, ?> column, final Object param) { return lt(Res.toCol(column), param); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition lte(final Column column, final Object param) {
		if ((param != null) && (param instanceof Column)) {
			return new Condition(null, new _Expression_COMPARE_TO(column, CompareType.LTE, (Column) param));
		} else {
			return new Condition(null, new _Expression_COMPARE(column, CompareType.LTE, param));
		}
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition lte(final SingularAttribute<?, ?> column, final Object param) { return lte(Res.toCol(column), param); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition gt(final Column column, final Object param) {
		if ((param != null) && (param instanceof Column)) {
			return new Condition(null, new _Expression_COMPARE_TO(column, CompareType.GT, (Column) param));
		} else {
			return new Condition(null, new _Expression_COMPARE(column, CompareType.GT, param));
		}
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition gt(final SingularAttribute<?, ?> column, final Object param) { return gt(Res.toCol(column), param); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition gte(final Column column, final Object param) {
		if ((param != null) && (param instanceof Column)) {
			return new Condition(null, new _Expression_COMPARE_TO(column, CompareType.GTE, (Column) param));
		} else {
			return new Condition(null, new _Expression_COMPARE(column, CompareType.GTE, param));
		}
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param param 参数或列
	 * @return 条件子句
	 */
	public static Condition gte(final SingularAttribute<?, ?> column, final Object param) { return gte(Res.toCol(column), param); }

	// ============================================ columnX in () ============================================ //
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public static Condition in(final Column column, final String paramsStr) {
		return new Condition(null, new _Expression_IN(column, true, paramsStr));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public static Condition in(final SingularAttribute<?, ?> column, final String paramsStr) { return in(Res.toCol(column), paramsStr); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public static Condition in(final Column column, final List<String> paramsList) {
		return new Condition(null, new _Expression_IN(column, true, paramsList));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public static Condition in(final SingularAttribute<?, ?> column, final List<String> paramsList) { return in(Res.toCol(column), paramsList); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public static Condition in(final Column column, final String[] paramsArr) {
		return new Condition(null, new _Expression_IN(column, true, paramsArr));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public static Condition in(final SingularAttribute<?, ?> column, final String[] paramsArr) { return in(Res.toCol(column), paramsArr); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public static Condition notIn(final Column column, final String paramsStr) {
		return new Condition(null, new _Expression_IN(column, false, paramsStr));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public static Condition notIn(final SingularAttribute<?, ?> column, final String paramsStr) { return notIn(Res.toCol(column), paramsStr); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public static Condition notIn(final Column column, final List<String> paramsList) {
		return new Condition(null, new _Expression_IN(column, false, paramsList));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public static Condition notIn(final SingularAttribute<?, ?> column, final List<String> paramsList) { return notIn(Res.toCol(column), paramsList); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public static Condition notIn(final Column column, final String[] paramsArr) {
		return new Condition(null, new _Expression_IN(column, false, paramsArr));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public static Condition notIn(final SingularAttribute<?, ?> column, final String[] paramsArr) { return notIn(Res.toCol(column), paramsArr); }

	// ============================================ like ? ============================================ //
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public static Condition like(final Column column, final LikeType likeType, final String param) {
		return new Condition(null, new _Expression_LIKE(column, true, likeType, param));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public static Condition like(final SingularAttribute<?, ?> column, final LikeType likeType, final String param) { return like(Res.toCol(column), likeType, param); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public static Condition notLike(final Column column, final LikeType likeType, final String param) {
		return new Condition(null, new _Expression_LIKE(column, false, likeType, param));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public static Condition notLike(final SingularAttribute<?, ?> column, final LikeType likeType, final String param) { return notLike(Res.toCol(column), likeType, param); }

	// ============================================ isNull ============================================ //
	/**
	 * 创建条件子句
	 * @param column 列
	 * @return 条件子句
	 */
	public static Condition isNull(final Column column) {
		return new Condition(null, new _Expression_NULL(column, true));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @return 条件子句
	 */
	public static Condition isNull(final SingularAttribute<?, ?> column) { return isNull(Res.toCol(column)); }
	/**
	 * 创建条件子句
	 * @param column 列
	 * @return 条件子句
	 */
	public static Condition isNotNull(final Column column) {
		return new Condition(null, new _Expression_NULL(column, false));
	}
	/**
	 * 创建条件子句
	 * @param column 列
	 * @return 条件子句
	 */
	public static Condition isNotNull(final SingularAttribute<?, ?> column) { return isNotNull(Res.toCol(column)); }

	// ============================================ condition ============================================ //
	/**
	 * 创建条件子句
	 * @param condition 条件子句
	 * @return 条件子句
	 */
	public static Condition of(final Condition condition) {
		return new Condition(null, condition);
	}

	// ======================================================================================== and/or ======================================================================================== //
	private void checkComplex() {
		if (this.expression != null) {// 普通条件
			// 原对象是普通条件，需要先将原条件转为复合条件并存入原条件，再追加子句。
			this.conditions = new _Conditions();
			this.conditions.add(new Condition(null, this.expression));
			this.expression = null;
		} else {// 复合条件
			// 原对象是复合条件则直接追加子句即可
		}
	}
	private Condition and(final _Expression expression) {
		this.checkComplex();
		this.conditions.add(new Condition(true, expression));
		return this;
	}
	private Condition or(final _Expression expression) {
		this.checkComplex();
		this.conditions.add(new Condition(false, expression));
		return this;
	}
	// ============================================ column = ? ============================================ //
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param compareType 表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition and(final Column column, final CompareType compareType, final Object param) {
		return this.and(new _Expression_COMPARE(column, compareType, param));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param compareType 表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition and(final SingularAttribute<?, ?> column, final CompareType compareType, final Object param) { return this.and(Res.toCol(column), compareType, param); }
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param compareType 表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition or(final Column column, final CompareType compareType, final Object param) {
		return this.or(new _Expression_COMPARE(column, compareType, param));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param compareType 表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition or(final SingularAttribute<?, ?> column, final CompareType compareType, final Object param) { return this.or(Res.toCol(column), compareType, param); }

	// ============================================ columnX = columnY ============================================ //
	/**
	 * 拼接条件子句
	 * @param leftColumn 左边列
	 * @param compareType 表达式类型
	 * @param rightColumn 右边列
	 * @return 条件子句
	 */
	public Condition and(final Column leftColumn, final CompareType compareType, final Column rightColumn) {
		return this.and(new _Expression_COMPARE_TO(leftColumn, compareType, rightColumn));
	}
	/**
	 * 拼接条件子句
	 * @param leftColumn 左边列
	 * @param compareType 表达式类型
	 * @param rightColumn 右边列
	 * @return 条件子句
	 */
	public Condition and(final SingularAttribute<?, ?> leftColumn, final CompareType compareType, final SingularAttribute<?, ?> rightColumn) { return this.and(Res.toCol(leftColumn), compareType, Res.toCol(rightColumn)); }
	/**
	 * 拼接条件子句
	 * @param leftColumn 左边列
	 * @param compareType 表达式类型
	 * @param rightColumn 右边列
	 * @return 条件子句
	 */
	public Condition or(final Column leftColumn, final CompareType compareType, final Column rightColumn) {
		return this.or(new _Expression_COMPARE_TO(leftColumn, compareType, rightColumn));
	}
	/**
	 * 拼接条件子句
	 * @param leftColumn 左边列
	 * @param compareType 表达式类型
	 * @param rightColumn 右边列
	 * @return 条件子句
	 */
	public Condition or(final SingularAttribute<?, ?> leftColumn, final CompareType compareType, final SingularAttribute<?, ?> rightColumn) { return this.or(Res.toCol(leftColumn), compareType, Res.toCol(rightColumn)); }

	// ============================================ columnX in () ============================================ //
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public Condition and(final Column column, final boolean in, final String paramsStr) {
		return this.and(new _Expression_IN(column, in, paramsStr));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public Condition and(final SingularAttribute<?, ?> column, final boolean in, final String paramsStr) { return this.and(Res.toCol(column), in, paramsStr); }
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsStr 参数，使用特殊分隔符切分。
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public Condition or(final Column column, final boolean in, final String paramsStr) {
		return this.or(new _Expression_IN(column, in, paramsStr));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsStr 参数，使用特殊分隔符切分。
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 条件子句
	 */
	public Condition or(final SingularAttribute<?, ?> column, final boolean in, final String paramsStr) { return this.or(Res.toCol(column), in, paramsStr); }

	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public Condition and(final Column column, final boolean in, final List<String> paramsList) {
		return this.and(new _Expression_IN(column, in, paramsList));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public Condition and(final SingularAttribute<?, ?> column, final boolean in, final List<String> paramsList) { return this.and(Res.toCol(column), in, paramsList); }
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public Condition or(final Column column, final boolean in, final List<String> paramsList) {
		return this.or(new _Expression_IN(column, in, paramsList));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsList 参数
	 * @return 条件子句
	 */
	public Condition or(final SingularAttribute<?, ?> column, final boolean in, final List<String> paramsList) { return this.or(Res.toCol(column), in, paramsList); }

	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public Condition and(final Column column, final boolean in, final String[] paramsArr) {
		return this.and(new _Expression_IN(column, in, paramsArr));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public Condition and(final SingularAttribute<?, ?> column, final boolean in, final String[] paramsArr) { return this.and(Res.toCol(column), in, paramsArr); }
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public Condition or(final Column column, final boolean in, final String[] paramsArr) {
		return this.or(new _Expression_IN(column, in, paramsArr));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsArr 参数
	 * @return 条件子句
	 */
	public Condition or(final SingularAttribute<?, ?> column, final boolean in, final String[] paramsArr) { return this.or(Res.toCol(column), in, paramsArr); }

	// ============================================ like ? ============================================ //
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param like true：LIKE；false：NOT LIKE；
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition and(final Column column, final boolean like, final LikeType likeType, final String param) {
		return this.and(new _Expression_LIKE(column, like, likeType, param));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param like true：LIKE；false：NOT LIKE；
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition and(final SingularAttribute<?, ?> column, final boolean like, final LikeType likeType, final String param) { return this.and(Res.toCol(column), like, likeType, param); }
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param like true：LIKE；false：NOT LIKE；
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition or(final Column column, final boolean like, final LikeType likeType, final String param) {
		return this.or(new _Expression_LIKE(column, like, likeType, param));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param like true：LIKE；false：NOT LIKE；
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 条件子句
	 */
	public Condition or(final SingularAttribute<?, ?> column, final boolean like, final LikeType likeType, final String param) { return this.or(Res.toCol(column), like, likeType, param); }

	// ============================================ isNull ============================================ //
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param isNull true：IS NULL；false：IS NOT NULL；
	 * @return 条件子句
	 */
	public Condition and(final Column column, final boolean isNull) {
		return this.and(new _Expression_NULL(column, isNull));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param isNull true：IS NULL；false：IS NOT NULL；
	 * @return 条件子句
	 */
	public Condition and(final SingularAttribute<?, ?> column, final boolean isNull) { return this.and(Res.toCol(column), isNull); }
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param isNull true：IS NULL；false：IS NOT NULL；
	 * @return 条件子句
	 */
	public Condition or(final Column column, final boolean isNull) {
		return this.or(new _Expression_NULL(column, isNull));
	}
	/**
	 * 拼接条件子句
	 * @param column 列
	 * @param isNull true：IS NULL；false：IS NOT NULL；
	 * @return 条件子句
	 */
	public Condition or(final SingularAttribute<?, ?> column, final boolean isNull) { return this.or(Res.toCol(column), isNull); }

	// ============================================ condition ============================================ //
	/**
	 * 拼接条件子句
	 * @param condition 条件子句
	 * @return 条件子句
	 */
	public Condition and(final Condition condition) {
		this.checkComplex();
		condition.conditionType = true;
		condition.outer = false;
		this.conditions.add(condition);
		return this;
	}
	/**
	 * 拼接条件子句
	 * @param condition 条件子句
	 * @return 条件子句
	 */
	public Condition or(final Condition condition) {
		this.checkComplex();
		condition.conditionType = false;
		condition.outer = false;
		this.conditions.add(condition);
		return this;
	}

}
